#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "version.h"

/** @addtogroup AUTO_VERSION_MODULE
 * @{
 */
#define DEBUG 0
#if DEBUG
#define DEBUG_PRINTF(...) printf(##__VA_ARGS__)
#else
#define DEBUG_PRINTF(...)
#endif

#define YEAR ((((__DATE__[7] - '0') * 10 + (__DATE__[8] - '0')) * 10 + (__DATE__[9] - '0')) * 10 + (__DATE__[10] - '0'))

/**月份简写
January (Jan)---Febuary (Feb)---March (Mar)---April (Apr)---May (May)---June (Jun)--
July (Jul)---August (Aug)---September (Sep)---October (Oct)---November (Nov)---SDecember (Dec)--
*/

#define MONTH (__DATE__[2] == 'n'   ? (__DATE__[0] == 'J' ? 1 : 6) \
               : __DATE__[2] == 'b' ? 2                            \
               : __DATE__[2] == 'r' ? (__DATE__[0] == 'M' ? 3 : 4) \
               : __DATE__[2] == 'y' ? 5                            \
               : __DATE__[2] == 'l' ? 7                            \
               : __DATE__[2] == 'g' ? 8                            \
               : __DATE__[2] == 'p' ? 9                            \
               : __DATE__[2] == 't' ? 10                           \
               : __DATE__[2] == 'v' ? 11                           \
                                    : 12)

#define DAY ((__DATE__[4] == ' ' ? 0 : __DATE__[4] - '0') * 10 + (__DATE__[5] - '0'))
#define HOUR ((__TIME__[0] == ' ' ? 0 : __TIME__[0] - '0') * 10 + (__TIME__[1] - '0'))
#define MINUTE ((__TIME__[3] == ' ' ? 0 : __TIME__[3] - '0') * 10 + (__TIME__[4] - '0'))
#define SECOND ((__TIME__[6] == ' ' ? 0 : __TIME__[6] - '0') * 10 + (__TIME__[7] - '0'))
#define DATE_AS_INT (((YEAR - 2000) * 12 + MONTH) * 31 + DAY)

/**
 * @brief This structure holds the values of version.
 */
typedef union
{
    struct
    {
        uint16_t dd : 5;  /*!< day*/
        uint16_t mm : 4;  /*!< month*/
        uint16_t yy : 6;  /*!< year*/
        uint16_t std : 1; /*!< std or not*/
    } bits;
    uint16_t word; /*!< version in int*/
} version_t;
typedef union
{
    struct
    {
        uint16_t dd : 5;  /*!< day*/
        uint16_t mm : 4;  /*!< month*/
        uint16_t yy : 6;  /*!< year*/
        uint16_t std : 1; /*!< std or not*/
    } bits;
    uint16_t word; /*!< version in int*/
} date_t;
typedef union
{
    struct
    {
        uint16_t mm : 6;  /*!< minute*/
        uint16_t hh : 5;  /*!< hour*/
        uint16_t res : 5; /*!< reserved*/
    } bits;
    uint16_t word; /*!< version in int*/
} time_t;
/**
  * @brief 编译时自动生成版本号.
  @verbatim
  *|-----------------------------------|
  *|    b15   | b14~9   | b8~5  | b4~0 |
  *|-----------------------------------|
  *|std or not| year    | month | day  |
  *|-----------------------------------|
  *| (1)  (0) | 20+xx   |  xx   | xx   |
  *|-----------------------------------|.
  @endverbatim
  * @retval 版本号.
  */
uint16_t get_version(vertype_t vt)
{
    version_t v;
    v.bits.std = vt;
    v.bits.yy = YEAR - 2000;
    v.bits.mm = MONTH;
    v.bits.dd = DAY;
#if DEBUG
    {
        const char *c[2] = {"test", "standard"};
        DEBUG_PRINTF("\r\nAppVersion is %d[%d.%d.%d.%s]", v.word, v.bits.yy, v.bits.mm, v.bits.dd, c[v.bits.std]);
    }
#endif
    return v.word;
}

/**
 * @brief 生成编译时刻日期编码
 * @return 编码
 */
uint16_t get_date_code(void)
{
    date_t v;
    v.bits.std = 0;
    v.bits.yy = YEAR - 2000;
    v.bits.mm = MONTH;
    v.bits.dd = DAY;
    return v.word;
}
/**
 * @brief 生成编译时刻时间编码
 * @return 编码
 */
uint16_t get_time_code(void)
{
    time_t v;
    v.bits.mm = MINUTE;
    v.bits.hh = HOUR;
    return v.word;
}
/**
 * @brief 生成编译时刻日期时间编码
 * @return 编码
 */
uint32_t get_date_time_code(void)
{
    date_time_t v;
    v.bits.yy = YEAR - 2000;
    v.bits.mm = MONTH;
    v.bits.dd = DAY;
    v.bits.hr = HOUR;
    v.bits.min = MINUTE;
    v.bits.sec = SECOND;
#if DEBUG
    DEBUG_PRINTF("y%d m%d d%d h%d m%d s%d\n", v.bits.yy, v.bits.mm, v.bits.dd, v.bits.hr, v.bits.min, v.bits.sec);
#endif
    return v.dword;
}
/**
 * @brief 生成指定日期的版本编码
 * @param s 0 标准版 1 测试版
 * @param y 年 [2000,2063]
 * @param m 月 [1,12]
 * @param d 日 [1,31]
 * @return 版本编码
 */
uint16_t set_version(uint8_t s, uint16_t y, uint8_t m, uint8_t d)
{
    version_t v;
    v.bits.std = s ? 1 : 0;
    v.bits.yy = y - 2000;
    v.bits.mm = m;
    v.bits.dd = d;
    return v.word;
}
/** @} */
/** @} */
